from pymodbus.client import ModbusSerialClient
import time
import random

# 板子有4个485和2个232接口，定义如下
serial485_1 = '/dev/tty485_1'
# serial485_2 = '/dev/tty485_2'
# serial485_3 = '/dev/tty485_3'
# serial485_4 = '/dev/tty485_4'

# 这里选择的是板子的485-1接口和io主机485连接的
client = ModbusSerialClient(method='rtu', port=serial485_1, baudrate=9600, timeout=1)
if client.connect():
    print("Modbus RTU Client Connected")
else:
    print("Failed to connect to Modbus RTU Client")
    

# 读取线圈状态
def read_coils(slave_addr, starting_address, coil_quantity):
    """
    读取线圈状态(DO输出状态)
    参数:
        slave_addr (int): 从机地址
        starting_address (int): 起始线圈地址
        coil_quantity (int): 要读取的线圈数量
    功能:
        读取指定从机的线圈状态，通常用于读取数字输出(DO)的当前状态
    """
    response = client.read_coils(starting_address, coil_quantity, unit=slave_addr)
    if not response.isError():
        print('Coil status:', [int(coil) for coil in response.bits])
    else:
        print(response)

#读取离散输入状态
def read_discrete_inputs(slave_addr, starting_address, input_quantity):
    """
    读取离散输入状态(DI输入状态)
    参数:
        slave_addr (int): 从机地址
        starting_address (int): 起始输入地址
        input_quantity (int): 要读取的输入数量
    功能:
        读取指定从机的离散输入状态，通常用于读取数字输入(DI)的当前状态
    """
    response = client.read_discrete_inputs(starting_address, input_quantity, unit=slave_addr)
    if not response.isError():
        print('Input status:', [int(input) for input in response.bits])
    else:
        print(response)

# 读取保持寄存器数值
def read_holding_registers(slave_addr, starting_address, register_quantity, signed=True):
    """
    读取保持寄存器数值
    参数:
        slave_addr (int): 从机地址
        starting_address (int): 起始寄存器地址
        register_quantity (int): 要读取的寄存器数量
        signed (bool): 是否为有符号数,默认为True
    功能:
        读取指定从机的保持寄存器数值，通常用于读取可读写的配置参数或状态值
    """
    response = client.read_holding_registers(starting_address, register_quantity, unit=slave_addr)
    if not response.isError():
        print('Holding register value:', response.registers)
    else:
        print(response)


def read_input_registers(slave_addr, starting_address, register_quantity, signed=True):
    """
    读取输入寄存器数值(AI模拟输入值)
    参数:
        slave_addr (int): 从机地址
        starting_address (int): 起始寄存器地址
        register_quantity (int): 要读取的寄存器数量
        signed (bool): 是否为有符号数,默认为True
    功能:
        读取指定从机的输入寄存器数值，通常用于读取模拟输入(AI)的采样值
    """
    response = client.read_input_registers(starting_address, register_quantity, unit=slave_addr)
    if not response.isError():
        print('Input register value:', response.registers)
    else:
        print(response)

#写入单个线圈状态
def write_single_coil(slave_addr, output_address, output_value):
    """
    写入单个线圈状态(控制单个DO输出)
    参数:
        slave_addr (int): 从机地址
        output_address (int): 输出线圈地址
        output_value (bool): 输出值,True为开启,False为关闭
    功能:
        控制指定从机的单个数字输出(DO)的开关状态
    """
    response = client.write_coil(output_address, output_value, unit=slave_addr)
    if not response.isError():
        print('Wrote single coil:', output_value)
    else:
        print(response)

#写入单个寄存器数值
def write_single_register(slave_addr, register_address, register_value, signed=True):
    """
    写入单个寄存器数值
    参数:
        slave_addr (int): 从机地址
        register_address (int): 寄存器地址
        register_value (int): 要写入的数值
        signed (bool): 是否为有符号数,默认为True
    功能:
        向指定从机的单个保持寄存器写入数值，通常用于设置配置参数
    """
    response = client.write_register(register_address, register_value, unit=slave_addr)
    if not response.isError():
        print('Wrote single register:', register_value)
    else:
        print(response)

# 写入多个线圈状态
def write_multiple_coils(slave_addr, starting_address, output_values):
    """
    写入多个线圈状态(批量控制DO输出)
    参数:
        slave_addr (int): 从机地址
        starting_address (int): 起始线圈地址
        output_values (list): 输出值列表,每个元素为bool类型
    功能:
        批量控制指定从机的多个数字输出(DO)的开关状态
    """
    response = client.write_coils(starting_address, output_values, unit=slave_addr)
    if not response.isError():
        print('Wrote multiple coils:', output_values)
    else:
        print(response)

# 写入多个寄存器数值
def write_multiple_registers(slave_addr, register_address, register_values, signed=True):
    """
    写入多个寄存器数值
    参数:
        slave_addr (int): 从机地址
        register_address (int): 起始寄存器地址
        register_values (list): 要写入的数值列表
        signed (bool): 是否为有符号数,默认为True
    功能:
        向指定从机的多个保持寄存器批量写入数值，通常用于批量设置配置参数
    """
    response = client.write_registers(register_address, register_values, unit=slave_addr)
    if not response.isError():
        print('Wrote multiple registers:', register_values)
    else:
        print(response)


def read_virtual_soil_sensor(addr=1, retries=2, delay_ms=100):
    '''
    brief: 返回虚拟的水分传感器数据（用于测试）
    return: 返回列表数据,格式与read_soil_sensor相同
    '''
    time.sleep(0.2)  # 模拟读取延时
    soil = random.randint(20, 80)  # 湿度20%-80%
    temperature = random.randint(150, 350)  # 温度15-35度的10倍表示
    return (soil, temperature)
